<?php
namespace base;

use base\tools\Str;
use base\container\Context;
use base\container\ServiceLogic;
use Closure;
use Exception;
use think\facade\Db;

/**
 * 逻辑服务容器
 */
class ServiceContainer
{

    /**
     * 逻辑服务命名空间
     * @var string
     */
    protected $servicePath = 'app\\service\\';

    /**
     * 当前执行的逻辑服务
     * @var BaseService
     */
    protected $service;

    /**
     * 当前执行方法
     *
     * @var mixed
     */
    protected $method;
    
    /**
     * 当前服务调用者
     * @var array
     */
    protected $caller = [];

    /**
     * 容器上下文
     * @var Context
     */
    protected $context;

    /**
     * 服务逻辑对象
     * @var ServiceLogic
     */
    protected $serivceLogic; 

    /**
     * 工作流对象
     * @var array
     */
    protected $flow;

    /**
     * 逻辑服务执行后下一步调用
     * @var array
     */
    protected $next = [];

    /**
     * 初始化逻辑服务容器
     * @access public
     * @return static
     */
    public static function initInstance($serviceName,$caller,$namespace='')
    {
        $container = new static;

        $container->setNamespace($namespace)
                  ->setService($serviceName)
                  ->setCaller($caller)
                  ->setContext($container);

        return $container;
        
    }

    /**
     * 设置服务命名空间
     *
     * @param string $namespace
     * @return ServiceContainer
     */
    public function setNamespace($namespace)
    {
        if($namespace)$this->servicePath = $namespace;

        return $this;
    }

    /**
     * 设置逻辑服务实例
     *
     * @param string $serviceName
     * @return ServiceContainer
     */
    public function setService($serviceName)
    {
        $serviceInfo = Db::table('ykfac_service')->where(['alias'=>$serviceName])->find();

        if(!$serviceInfo)throw new Exception("未找到服务:".$serviceName, 0);

        $class = ($serviceInfo['service_namespace']??$this->servicePath).Str::studly($serviceInfo['service_class']);

        if(!class_exists($class))throw new Exception("未找到服务:".$class, 0);

        $this->service = new $class();

        $this->service->container = $this;

        $this->service->service_info = $serviceInfo;

        return $this;
        
    }

    /**
     * 设置服务调用者
     *
     * @param array $caller
     * @return ServiceContainer
     */
    public function setCaller($caller)
    {
        $this->caller = $caller;

        return $this;
    }

    /**
     * 设置服务上下文
     *
     * @param ServiceContainer $container
     * @return void
     */
    private function setContext($container){
        $this->context = new Context($container);
    }

    /**
     * 设置服务方法
     *
     * @param string $method
     * @return void
     */
    private function setMethod($method)
    {
        $methodInfo = Db::table('ykfac_service_method')->where(['service_id'=>$this->service->service_info['service_id'],'method_name'=>$method])->find();
        if(!$methodInfo)throw new Exception("方法不存在:".get_class($this->service)."::".$method, 0);
        $this->method = $methodInfo;
    }

    /**
     * 执行服务逻辑
     *
     * @param string $position
     * @return void
     */
    public function execLogic($position,&...$param)
    {
       $res =  $this->serivceLogic->exec($position,...$param);
       if(!$res)return_error(['info'=>$this->context->errInfo]);
    }

    /**
     * 调用服务方法
     *
     * @param string $method
     * @param array $args
     * @return void
     */
    public function __call($method,$args)
    {
        if(!method_exists($this->service,$method))throw new Exception("方法不存在:".get_class($this->service)."::".$method, 0);

        $this->setMethod($method);

        $this->serivceLogic = new ServiceLogic($this);

        $res = call_user_func_array([$this->service,$method],$args);

        if(!$res)return_error(['info'=>$this->context->errInfo]);

        return $res;

    }

    /**
     * 获取容器属性
     *
     * @param string $name
     * @return void
     */
    public function __get($name)
    {
        return $this->$name;
    }

}